import json
import re
import logging
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator, EmptyPage
from django.http import HttpResponse
from django.http import HttpResponseBadRequest
from django.http import HttpResponseNotFound
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import merge_cookie_to_redis
from apps.goods.models import SKU
from apps.oauth.utils import generate_safe_openid, load_true_openid
from apps.orders.models import OrderInfo
from apps.users.models import User, Address
from apps.users.utils import check_verify_url
from celery_tasks.sms.tasks import send_sms_code
from utils.response_code import RETCODE


class RegisterView(View):
    # 展示用户注册界面
    def get(self, request):

        return render(request, 'register.html')

    # 提交表单数据
    # 接收数据（从POST.get（‘对应前端标签名字’）中获得）
    # 验证数据（验证参数是否接全，验证各项参数是否符合规则，如果不符合则badrequest）
    # 数据入库（try：模型类.objects.filter(条件)，except：return badrequest）
    # 返回响应（注册成功，设置会话状态，跳转到首页）
    def post(self, request):

        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        pic_code = request.POST.get('pic_code')
        sms_code = request.POST.get('sms_code')
        allow = request.POST.get('allow')

        if not all([username, password2, password, mobile, pic_code, sms_code, allow]):
            return HttpResponseBadRequest('参数不全')

        if not re.match(r'[a-zA-Z0-9_-]{5,20}', username):
            return HttpResponseBadRequest('用户名不符合规则')

        if not re.match(r'[a-zA-Z0-9]{8,20}', password):
            return HttpResponseBadRequest('密码不符合规则')

        if password != password2:
            return HttpResponseBadRequest('密码不一致')

        if not re.match(r'1[3-9]\d{9}', mobile):
            return HttpResponseBadRequest('手机号不符合规则')

        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
            logger.error(e)
            return render(request, 'register.html', {'register_error_massage': '数据库链接错误'})

        from django.contrib.auth import login
        login(request, user)
        return redirect(reverse('contents:index'))


class UsernameCountView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return JsonResponse({'count': count})


class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({'count': count})


from django.contrib.auth import login, authenticate, logout


class LoginView(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        rembered = request.POST.get('remembered')
        next = request.GET.get('next')
        if not all([username, password]):
            return HttpResponseBadRequest('参数不全')
        if not re.match(r'[a-zA-Z0-9_]{5,20}', username):
            return HttpResponseBadRequest('用户名不符合规则')
        if not re.match(r'[a-zA-Z0-9_]{8,20}', password):
            return HttpResponseBadRequest('密码不符合规则')
        user = authenticate(username=username, password=password)
        if user is None:
            return HttpResponseBadRequest('账号或密码错误')
        login(request, user)
        if rembered == 'on':
            request.session.set_expiry(None)
        else:
            request.session.set_expiry(0)
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))
        response.set_cookie('username', user.username)
        merge_cookie_to_redis(request, user, response)
        return response


class LogoutView(View):
    def get(self, request):
        logout(request)
        response = redirect(reverse('users:login'))
        response.delete_cookie('username')
        return response


class CenterView(LoginRequiredMixin, View):
    login_url = '/login/'

    def get(self, request):
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active,

        }
        return render(request, 'user_center_info.html', context=context)


class EmailView(View):
    def put(self, request):
        user = request.user
        body_dict = json.loads(request.body.decode())

        email = body_dict.get('email')
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '邮箱格式不正确'})
        try:
            user.email = email
            user.save()
        except Exception as e:
            return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '保存失败'})

        from celery_tasks.email.tasks import send_active_email
        send_active_email.delay(email, request.user.id)
        return JsonResponse({'code': RETCODE.OK})


class EmailActiveView(View):
    def get(self, request):
        token = request.GET.get('token')
        if token is None:
            return HttpResponseBadRequest('参数不全')
        userid = check_verify_url(token)

        if userid is None:
            return HttpResponseBadRequest('参数错误')
        try:
            user = User.objects.get(id=userid)
        except Exception:
            return HttpResponseBadRequest('没有此用户')
        user.email_active = True
        user.save()
        return HttpResponse('OK')


class UserCenterSiteView(LoginRequiredMixin, View):
    def get(self, request):
        # 1.根据条件查询
        address = Address.objects.filter(user=request.user, is_deleted=False)
        # 2.获取数据
        # 前端是通过vue来渲染的,将对象列表转换为字典列表
        address_list = []
        for item in address:
            address_list.append({
                "id": item.id,
                "title": item.title,
                "receiver": item.receiver,
                "province": item.province.name,
                "province_id": item.province_id,
                "city": item.city.name,
                "city_id": item.city_id,
                "district": item.district.name,
                "district_id": item.district_id,
                "place": item.place,
                "mobile": item.mobile,
                "tel": item.tel,
                "email": item.email,
            })
        context = {
            'default_address_id': request.user.default_address_id,
            'addresses': address_list,
        }
        return render(request, 'user_center_site.html', context=context)


logger = logging.getLogger('django')


class AddAddressesView(View):
    def post(self, request):

        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('参数不全')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('电话号码不符合格式')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return HttpResponseBadRequest('固话不符合格式')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')

        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)

        new_address = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'address': new_address})


class AddressesUpdateView(View):
    def put(self, request, address_id):

        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('参数不全')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('电话号码不符合格式')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return HttpResponseBadRequest('固话不符合格式')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')

        try:
            result = Address.objects.filter(pk=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新失败,请稍后再试'})
        if result == 0:
            return HttpResponseBadRequest('更新失败')
        address = Address.objects.get(pk=address_id)
        new_address = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        return JsonResponse({'code': RETCODE.OK, 'errmsg': '更新成功', 'address': new_address})

    def delete(self, request, address_id):
        try:
            Address.objects.filter(pk=address_id).update(is_deleted=True)
        except Address.DoesNotExist:
            return JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '没有此记录'})
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})


class AddressDefaultView(View):
    def put(self, request, address_id):
        if address_id is None:
            return HttpResponseBadRequest('参数不全')
        else:
            try:
                user = request.user
                user.default_address_id = address_id
                user.save()
            except Exception as e:
                logger.error(e)
                return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})
            return JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})


class TitleUpdateView(View):
    def put(self, request, address_id):
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        try:
            address = Address.objects.get(pk=address_id)
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': RETCODE.SESSIONERR, 'errmsg': '用户未登录'})
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})


class ChangePasswordView(LoginRequiredMixin, View):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        user_id = request.user.id
        old_pwd = request.POST.get('old_password')
        new_pwd = request.POST.get('new_password')
        new_cpwd = request.POST.get('new_password2')
        if not all([old_pwd, new_pwd, new_cpwd]):
            return HttpResponseBadRequest('参数不足')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_pwd):
            return HttpResponseBadRequest('参数错误')
        if new_pwd != new_cpwd:
            return HttpResponseBadRequest('两次密码不一致')
        if not request.user.check_password(old_pwd):
            return render(request, 'user_center_pass.html', {'origin_password_errmsg': '原始密码错误'})

        try:
            request.user.set_password(new_pwd)
            request.user.save()
        except Exception as e:
            logger.error(e)
            return render(request, 'user_center_pass.html', {'change_password_errmsg': '修改密码失败'})
        logout(request)

        response = redirect(reverse('users:login'))

        response.delete_cookie('username')

        return response


class HistoryView(LoginRequiredMixin, View):
    def post(self, request):
        dict = json.loads(request.body.decode())
        sku_id = dict.get('sku_id')
        try:
            sku = SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': RETCODE.NODATAERR, 'errmsg': '没有此商品'})
        redis_coon = get_redis_connection('history')
        pl = redis_coon.pipeline()
        user_id = request.user.id
        pl.lrem('history:%s' % user_id, 0, sku_id)
        pl.lpush('history:%s' % user_id, sku_id)
        pl.ltrim('history:%s' % user_id, 0, 4)
        pl.execute()
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        user_id = request.user.id
        redis_coon = get_redis_connection('history')
        sku_ids = redis_coon.lrange('history:%s' % user_id, 0, 4)
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(pk=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
            })

        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})


class FindPwdView(View):
    def get(self, request):
        return render(request, 'find_password.html')


class FindPwdFirstView(View):
    def get(self, request, username):
        image_code = request.GET.get('text')
        image_code_id = request.GET.get('image_code_id')
        if not all([username, image_code]):
            return HttpResponseBadRequest('参数不足')
        try:
            if re.match('^1[3-9]\d{9}$', username):
                user = User.objects.get(mobile=username)
                mobile = username
            else:
                user = User.objects.get(username=username)
                mobile = user.mobile
        except User.DoesNotExist:
            return JsonResponse(status=400)
        redis_conn = get_redis_connection('code')
        redis_code = redis_conn.get('img:%s' % image_code_id)
        if redis_code is None:
            return HttpResponseBadRequest('验证码已过期')
        if redis_code.decode().lower() != image_code.lower():
            return JsonResponse(status=400)
        redis_conn.delete('img:%s' % image_code_id)
        user_id = user.id
        access_token = generate_safe_openid(user_id).decode()
        return JsonResponse({
            'mobile': mobile,
            'access_token': access_token
        })


class SendSmsCodeView(View):
    def get(self, request):
        access_token = request.GET.get('access_token')
        user_id = load_true_openid(access_token)
        try:
            user = User.objects.get(pk=user_id)
            mobile = user.mobile
        except User.DoesNotExist:
            return HttpResponseBadRequest('用户不存在')
        from random import randint
        sms_code = '%06d' % randint(0, 999999)
        redis_conn = get_redis_connection('code')
        pl = redis_conn.pipeline()
        pl.setex('sms:%s' % mobile, 300, sms_code)
        pl.setex('send_flag:%s' % mobile, 300, 1)
        pl.execute()
        send_sms_code.delay(mobile, sms_code)
        return HttpResponse('OK')


class FindPwdSeconedView(View):
    def get(self, request, username):

        sms_code = request.GET.get('sms_code')
        if sms_code is None:
            return HttpResponseBadRequest('请填写图片验证码')
        try:
            if re.match('^1[3-9]\d{9}$', username):
                user = User.objects.get(mobile=username)
                mobile = username
            else:
                user = User.objects.get(username=username)
                mobile = user.mobile
        except User.DoesNotExist:
            return JsonResponse(status=400)
        user_id = user.id
        conn = get_redis_connection('code')
        redis_code = conn.get('sms:%s' % mobile)
        if redis_code.decode() != sms_code:
            return JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '短信验证码错误'})
        access_token = generate_safe_openid(user_id).decode()
        return JsonResponse({
            'user_id': user.id,
            'access_token': access_token
        })


class FindPwdThirdView(View):
    def post(self, request, user_id):
        data = json.loads(request.body.decode())
        password = data.get('password')
        password2 = data.get('password2')
        access_token = data.get('access_token')
        if not all([password, password2, access_token]):
            return HttpResponseBadRequest('参数不足')
        if password != password2:
            return HttpResponseBadRequest('两次密码不一致')
        if access_token is None:
            return HttpResponseBadRequest('清进行身份验证之后在修改')
        user_msg = load_true_openid(access_token)
        if int(user_id) == user_msg:
            try:
                user = User.objects.get(pk=user_id)
            except User.DoesNotExist:
                return HttpResponseBadRequest('用户不存在')
            user.set_password(password)
            user.save()
        else:
            return JsonResponse('身份验证未通过', status=400)
        return JsonResponse({'code': RETCODE.OK, 'message': '修改密码成功'})


class OrderListView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        page_num = int(page_num)
        user = request.user
        orders = user.orders.all()
        for order in orders:
            order.details = []
            order_goods = order.skus.all().order_by("-create_time")
            for good in order_goods:
                sku = good.sku
                sku.count = good.count
                sku.total_amount = sku.price * sku.count
                order.details.append(sku)
        try:
            paginator = Paginator(orders, 2)
            page = paginator.page(page_num)
            total_page = paginator.num_pages
        except EmptyPage:
            return HttpResponseNotFound('订单不存在')
        context = {
            'page': page,
            'total_page': total_page,
            'page_num': page_num
        }
        return render(request, 'user_center_order.html', context)
